﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Linq;
using System.Xml.Linq;

using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.web;
using umbraco.cms.presentation.Trees;
using System.Text.RegularExpressions;

namespace Xuntos.uTreeFormat.Events
{
    public class ApplicationEventsHandler : ApplicationBase
    {
        public ApplicationEventsHandler()
        {
            BaseTree.BeforeNodeRender += new BaseTree.BeforeNodeRenderEventHandler(BaseTree_BeforeNodeRender);
        }

        void BaseTree_BeforeNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e)
        {
            if (node.NodeType != "content")
            {
                // Do nothing, not interesting at the moment.
                return;
            }

            string configCacheKey = "Xuntos.uTreeFormat.config";
            XDocument config = (XDocument)HttpContext.Current.Cache.Get(configCacheKey);
            if (config == null)
            {
                config = XDocument.Load(umbraco.IO.IOHelper.MapPath(@"~/config/Xuntos.uTreeFormat.config"));
                HttpContext.Current.Cache.Add(
                    configCacheKey,
                    config,
                    null,
                    DateTime.Now.AddHours(1),
                    //DateTime.Now.AddSeconds(30),
                    System.Web.Caching.Cache.NoSlidingExpiration,
                    System.Web.Caching.CacheItemPriority.Normal, null);
            }

            var id = 0;
            int.TryParse(node.NodeID, out id);
            Document fullNode = new Document(id);

            string uTreeFormatCacheKey = string.Format("uTreeFormat_{0}_{1}_{2}", node.NodeType, fullNode.ContentType.Alias, fullNode.Published.ToString());

            string treeFormat = "";
            string treeFormatType = "";

            // Get the razor version
            treeFormat = (string)HttpContext.Current.Cache.Get(uTreeFormatCacheKey + "razor");
            if (string.IsNullOrEmpty(treeFormat))
            {
                // Fallback to the normal variant
                treeFormat = (string)HttpContext.Current.Cache.Get(uTreeFormatCacheKey);
            }
            else
            {
                // If it's razor, set the type to razor for the rendering
                treeFormatType = "razor";
            }

            if (string.IsNullOrEmpty(treeFormat))
            {
                XElement treeFormatNode = null;
                try
                {
                    // Razor cannot work for unpublished items, so do a fallback to none-razor formatting
                    if (fullNode.Published)
                    {
                        treeFormatNode = config.Descendants(node.NodeType).Descendants(fullNode.ContentType.Alias).First();
                        treeFormat = treeFormatNode.Value;
                        try
                        {
                            treeFormatType = treeFormatNode.Attributes(XName.Get("type")).First().Value;
                        }
                        catch (Exception)
                        {
                            // Do nothing
                        }
                    }
                    else
                    {
                        treeFormatNode =
                            config.Descendants(node.NodeType).Descendants(fullNode.ContentType.Alias).Where(n => n.Attribute(XName.Get("type")) == null || n.Attribute(XName.Get("type")).Value != "razor").First();
                        treeFormat = treeFormatNode.Value;
                    }
                }
                catch (Exception exTreeFormat)
                {
                    try
                    {
                        //treeFormat = config.Descendants(node.NodeType).Descendants("__default").First().Value;
                        // Razor cannot work for unpublished items, so do a fallback to none-razor formatting
                        if (fullNode.Published)
                        {
                            treeFormatNode = config.Descendants(node.NodeType).Descendants("__default").First();
                            treeFormat = treeFormatNode.Value;
                            try
                            {
                                treeFormatType = treeFormatNode.Attributes(XName.Get("type")).First().Value;
                            }
                            catch (Exception)
                            {
                                // Do nothing
                            }
                        }
                        else
                        {
                            treeFormatNode =
                                config.Descendants(node.NodeType).Descendants("__default").Where(n => n.Attribute(XName.Get("type")) == null || n.Attribute(XName.Get("type")).Value != "razor").First();
                            treeFormat = treeFormatNode.Value;
                        }
                    }
                    catch (Exception)
                    {
                        treeFormat = config.Descendants("__default").First().Value;
                    }
                }
                SetTreeFormatCache(treeFormat, uTreeFormatCacheKey + treeFormatType);
            }
            string nodeFormat = treeFormat;
            try
            {
                if (treeFormatType == "razor")
                {
                    if (node.NodeType == "content")
                    {
                        umbraco.MacroEngines.RazorMacroEngine rme = new umbraco.MacroEngines.RazorMacroEngine();
                        umbraco.cms.businesslogic.macro.MacroModel mm = new umbraco.cms.businesslogic.macro.MacroModel();
                        mm.Alias = string.Format("utreeFormat_{0}", fullNode.ContentType.Alias);
                        mm.Name = mm.Alias;
                        mm.MacroType = umbraco.cms.businesslogic.macro.MacroTypes.Script;
                        mm.ScriptCode = treeFormat;
                        mm.ScriptLanguage = "cshtml";
                        // This cannot work for unpublished items. See check above.
                        umbraco.interfaces.INode currentPage = (umbraco.interfaces.INode)(new umbraco.NodeFactory.Node(id));

                        nodeFormat = rme.ExecuteRazor(mm, currentPage);
                    }
                }
                else
                {
                    MatchCollection matches = Regex.Matches(treeFormat, @"\{(.*?)\}");

                    foreach (Match item in matches)
                    {
                        try
                        {
                            switch (item.Value.ToLower())
                            {
                                case "{id}":
                                    nodeFormat = nodeFormat.Replace(item.Value, id.ToString());
                                    break;
                                case "{createdate}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.CreateDateTime.ToString("yyyy-MM-dd HH:mm"));
                                    break;
                                case "{creatorid}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Creator.Id.ToString());
                                    break;
                                case "{creatorname}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Creator.Name);
                                    break;
                                case "{level}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Level.ToString());
                                    break;
                                case "{nodename}":
                                case "{name}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Text);
                                    break;
                                case "{niceurl}":
                                case "{url}":
                                case "{urlname}":
                                    nodeFormat = nodeFormat.Replace(item.Value, umbraco.library.NiceUrl(fullNode.Id));
                                    break;
                                case "{nodetypealias}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.ContentType.Alias);
                                    break;
                                case "{updatedate}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.UpdateDate.ToString("yyyy-MM-dd HH:mm"));
                                    break;
                                case "{version}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Version.ToString());
                                    break;
                                case "{writerid}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Writer.Id.ToString());
                                    break;
                                case "{writername}":
                                    nodeFormat = nodeFormat.Replace(item.Value, fullNode.Writer.Name);
                                    break;
                                case "{parent}":
                                case "{path}":
                                case "{sortorder}":
                                case "{template}":
                                    // Do nothing, useless
                                    break;
                                default:
                                    try
                                    {
                                        nodeFormat = nodeFormat.Replace(item.Value, fullNode.getProperty(item.Value.Replace("{", "").Replace("}", "")).Value.ToString());
                                    }
                                    catch (Exception exDefault)
                                    {
                                        // Do nothing
                                    }
                                    break;
                            }
                        }
                        catch (Exception exFormat)
                        {
                            nodeFormat = node.Text;
                        }
                    }
                }
            }
            catch (Exception exFormat)
            {
                nodeFormat = node.Text;
            }
            // Make tags work by encoding them, but this creates problems when creating new page, since tags are DANGEROUS :-)
            //node.Text = System.Net.WebUtility.HtmlEncode(nodeFormat).Replace("\n", "").Replace("\r", "").Trim();
            node.Text = nodeFormat.Replace("\n", "").Replace("\r", "").Trim();
            // Class toevoegen!!! Uit treeformat halen
        }
        private void SetTreeFormatCache(string treeFormat, string uTreeFormatCacheKey)
        {
            HttpContext.Current.Cache.Add(
                uTreeFormatCacheKey,
                treeFormat,
                null,
                DateTime.Now.AddHours(1),
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.Normal, null);
        }
    }
}